#include "EconomyLand.h"
#include "EconomyPlugin.h"
#include "Managers/GameManager.h"
#include <fstream>
#include "spdlog/fmt/fmt.h"
#include "Expand/PluginsManager.h"
#include "Expand/Plugins/AuthPlugin.h"
#include "Network/Client.h"
#include "Player/PlayerData.h"
#include "Subsystems/SubsystemPlayers.h"

#include "Components/ComponentBody.h"
#include "Components/ComponentPlayer.h"
#include "Components/ComponentMiner.h"


namespace Economy
{
    EconomyLand::~EconomyLand() {}

    void EconomyLand::load()
    {
        m_subsystemPlayers = GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>();
        m_authPlugin = GameSingleton::singletonPtr->getSingleton<PluginsManager>()->findPlugin<AuthPlugin>();

        std::ifstream stream;
        stream.open(fmt::format("{}/EconomyLand.json", EconomyPlugin::PluginDataDirectory));

        if (stream.is_open())
        {
            nlohmann::json jsonData;
            stream >> jsonData;
            Utils::GetJsonValue<uint32_t>(jsonData, m_reletUseTime, "reletUseTime", 1440);
            Utils::GetJsonValue<std::map<std::string, LandData>>(jsonData, m_landMap, "data", std::map<std::string, LandData>());
        }
        else
        {
            m_reletUseTime = 1440;      // 一天
        }
        stream.close();
    }

    void EconomyLand::save()
    {
        nlohmann::json jsonData = {
            {"reletUseTime", m_reletUseTime},
            {"data", m_landMap}};
        Utils::SaveTextFile(fmt::format("{}/EconomyLand.json", EconomyPlugin::PluginDataDirectory), jsonData.dump());
    }

    bool EconomyLand::getLandData(int32_t regionX, int32_t regionY, LandData *outLandData)
    {
        std::lock_guard<std::mutex> lk(m_landMapMutex);

        std::string key = fmt::format("{},{}", regionX, regionY);
        auto it = m_landMap.find(key);
        if(it != m_landMap.end())
        {
            outLandData = &(it->second);
            return true;
        }
        return false;
    }

    bool EconomyLand::getShellLandPrice(int32_t chunkX, int32_t chunkY, uint32_t &outMoney)
    {
        int32_t regionX = chunkX >> 4;
        int32_t regionY = chunkY >> 4;

        // 转为内部chunk位置
        chunkX &= 0x0F;
        chunkY &= 0x0F;

        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);

            // 优先判断正在售卖的领地
            const auto &shellHireLand = landDataPtr->shellLandVec;
            for (auto it = shellHireLand.begin(); it != shellHireLand.end(); ++it)
            {
                if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                {
                    outMoney = it->price;
                    return true;
                }
            }

            // 由于是租地的问题，所以玩家的领地也有可能交不起地租而被回收
            const auto &userHireLand = landDataPtr->userLandVec;
            for(auto it = userHireLand.begin(); it != userHireLand.end(); ++it)
            {
                if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                {
                    outMoney = it->price;
                    return true;
                }
            }
        }
        return false;
    }

    bool EconomyLand::getLandUserGuid(int32_t chunkX, int32_t chunkY, GameGuid &outGameGuid)
    {
        int32_t regionX = chunkX >> 4;
        int32_t regionY = chunkY >> 4;

        // 转为内部chunk位置
        chunkX &= 0x0F;
        chunkY &= 0x0F;

        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);
            
            const auto &userHireLand = landDataPtr->userLandVec;
            for(auto it = userHireLand.begin(); it != userHireLand.end(); ++it)
            {
                if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                {
                    outGameGuid = it->userGuid;
                    return true;
                }
            }
        }
        return false;
    }

    bool EconomyLand::haveAuth(int32_t regionX, int32_t regionY, const GameGuid &userGuid)
    {
        if(m_authPlugin->getLevelByGuid(userGuid) >= 100)
        {
            return true;
        }

        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);
            for(auto it = landDataPtr->authUserVec.begin(); it != landDataPtr->authUserVec.end();++it)
            {
                if(*it == userGuid)
                {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    bool EconomyLand::addAuth(int32_t regionX, int32_t regionY, const GameGuid &userGuid)
    {
        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);
            landDataPtr->authUserVec.push_back(userGuid);
            return true;
        }
        return false;
    }

    bool EconomyLand::removeAuth(int32_t regionX, int32_t regionY, const GameGuid &userGuid)
    {
        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);
            for(auto it = landDataPtr->authUserVec.begin(); it != landDataPtr->authUserVec.end();++it)
            {
                if(*it == userGuid)
                {
                    landDataPtr->authUserVec.erase(it);
                    return true;
                }
            }
        }
        return false;
    }

    bool EconomyLand::getLandDataMode(int32_t regionX, int32_t regionY, LandType &outType)
    {
        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            outType = landDataPtr->mode;
            return true;
        }
        return false;
    }

    void EconomyLand::setLandDataMode(int32_t regionX, int32_t regionY, LandType type)
    {
        m_landMapMutex.lock();

        std::string key = fmt::format("{},{}", regionX, regionY);
        auto it = m_landMap.find(key);
        if(it != m_landMap.end())
        {
            it->second.mode = type;
        }
        else
        {
            m_landMap.emplace(key, type);
        }

        m_landMapMutex.unlock();
    }

    bool EconomyLand::removeLandData(int32_t regionX, int32_t regionY)
    {
        std::lock_guard<std::mutex> lk(m_landMapMutex);

        std::string key = fmt::format("{},{}", regionX, regionY);
        auto it = m_landMap.find(key);
        if(it != m_landMap.end())
        {
            m_landMap.erase(it);
            return true;
        }
        return false;
    }

    bool EconomyLand::shellLandToUserLand(int32_t chunkX, int32_t chunkY, const GameGuid &userGuid)
    {
        int32_t regionX = chunkX >> 4;
        int32_t regionY = chunkY >> 4;

        // 转为内部chunk位置
        chunkX &= 0x0F;
        chunkY &= 0x0F;

        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);

            // 优先判断正在售卖的领地
            auto &shellHireLand = landDataPtr->shellLandVec;
            for (auto it = shellHireLand.begin(); it != shellHireLand.end(); ++it)
            {
                if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                {
                    landDataPtr->userLandVec.emplace_back(it->price, it->hireMoney, m_reletUseTime, userGuid, it->chunkPointStart, it->chunkPointEnd);
                    shellHireLand.erase(it);
                    return true;
                }
            }
        }
        return false;
    }

    bool EconomyLand::userLandSetNewUser(int32_t chunkX, int32_t chunkY, const GameGuid &userGuid)
    {
        int32_t regionX = chunkX >> 4;
        int32_t regionY = chunkY >> 4;

        // 转为内部chunk位置
        chunkX &= 0x0F;
        chunkY &= 0x0F;

        LandData *landDataPtr;
        if(getLandData(regionX, regionY, landDataPtr) == true)
        {
            std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);

            auto &userHireLand = landDataPtr->userLandVec;
            for(auto it = userHireLand.begin(); it != userHireLand.end(); ++it)
            {
                if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                {
                    it->userGuid = userGuid;
                    return true;
                }
            }
        }
        return false;
    }



    static const std::string titleText = "领地";

    constexpr const char *help1 = "\n"
                                  "/land    -查看自己脚下领地是谁的或价格及租金\n"
                                  "/land buy    -租用脚下的领地\n"
                                  "/land help    -查看领地有关的指令\n"
                                  "/land exit    -退租脚下的领地\n"
                                  "/land invite (玩家)    -站在自己领地上，然后给对应玩家权限\n"
                                  "/land uninvite (玩家)    -站在自己领地上，然后移除对应玩家权限\n"
                                  "/land invite clear    -站在自己领地上，然后清空其他玩家权限\n"
                                  "/land invite list    -查看自己领地上，哪些玩家有权限";

    constexpr const char *help2 = "\n"
                                  "/land    -查看自己脚下领地是谁的或价格及租金\n"
                                  "/land buy    -租用脚下的领地\n"
                                  "/land help    -查看领地有关的指令\n"
                                  "/land exit    -退租脚下的领地\n"
                                  "/land invite (玩家)    -站在自己领地上，然后给对应玩家权限\n"
                                  "/land uninvite (玩家)    -站在自己领地上，然后移除对应玩家权限\n"
                                  "/land invite clear    -站在自己领地上，然后清空其他玩家权限\n"
                                  "/land invite list    -查看自己领地上，哪些玩家有权限\n"

                                  "/land give (玩家)    -将自己脚下的强制租给对应的玩家，不需要首付\n"
                                  "/land set (玩家)    -修改自己脚下玩家领地的租用者\n"
                                  "/land region set (模式)    -修改自己脚下区域领地的模式\n"
                                  "/land region remove    -移除脚下的区域领地数据，玩家租用数据一并移除\n"
                                  "/land auth add (玩家)    -给对应玩家现自己脚下区域领地的权限\n"
                                  "/land auth remove (玩家)    -移除脚下区域领地对应玩家的权限\n"
                                  "/land auth clear    -清空脚下区域领地的权限表\n"
                                  "/land auth list    -查看脚下区域领地上，哪些玩家有权限";

    static const std::string normalHelp = help1;
    static const std::string proHelp = help2;

    void EconomyLand::sendHelpMessage(IPlugin::ChatObj &chatObj)
    {
        if (chatObj.m_isTerminal == true || m_authPlugin->getLevelByGuid(chatObj.m_client->guid) >= 100)
        {
            chatObj.sendMessage(titleText, proHelp);
        }
        else
        {
            chatObj.sendMessage(titleText, normalHelp);
        }
    }

    void EconomyLand::sendGuidMessage(const GameGuid& gameGuid, const std::string &message)
    {
        PlayerDataPtr playerData = m_subsystemPlayers->getPlayerDataByGuid(gameGuid);
        if(playerData != nullptr)
        {
            IPlugin::ChatObj chatObj(playerData->client, false);
            chatObj.sendMessage(titleText, message);
        }
    }

    void EconomyLand::sendPlayerMessage(PlayerDataPtr &playerDataPtr, const std::string &message)
    {
        // if (playerDataPtr != nullptr)
        {
            IPlugin::ChatObj chatObj(playerDataPtr->client, false);
            chatObj.sendMessage(titleText, message);
        }
    }

    void EconomyLand::processCmd(IPlugin::ChatObj &chatObj, std::vector<std::string> &cmdDataVec)
    {
        if (chatObj.m_isTerminal == true)
        {
            chatObj.sendMessage(titleText, "控制台不能使用该指令");
            return;
        }

        if(cmdDataVec.size() == 1)
        {
            Vector3 position;
            chatObj.m_client->playerData->componentPlayer->componentBody->getPosition(position);

            Point3 point = position.toPoint3();
            int32_t regionX = point.posX >> 8;
            int32_t regionY = point.posZ >> 8;
            int32_t chunkX = (point.posX >> 4) & 0x0F;
            int32_t chunkY = (point.posZ >> 4) & 0x0F;

            LandData *landDataPtr;
            if(getLandData(regionX, regionY, landDataPtr) == true)
            {
                std::lock_guard<std::mutex> lk(landDataPtr->landDataMutex);
                // 优先判断正在售卖的领地
                const auto &shellHireLand = landDataPtr->shellLandVec;
                for (auto it = shellHireLand.begin(); it != shellHireLand.end(); ++it)
                {
                    if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                    {
                        chatObj.sendMessage(titleText, fmt::format("你脚下的领地正在出售，首付 {} $，后续续租 {} $, 租用时间 {} 分钟", it->price, it->hireMoney, m_reletUseTime));
                        return;
                    }
                }
                // 由于是租地的问题，所以玩家的领地也有可能交不起地租而被回收
                const auto &userHireLand = landDataPtr->userLandVec;
                for(auto it = userHireLand.begin(); it != userHireLand.end(); ++it)
                {
                    if( it->chunkPointStart.posX <= chunkX && it->chunkPointStart.posY <= chunkY && it->chunkPointEnd.posX >= chunkX && it->chunkPointEnd.posY >= chunkY)
                    {
                        std::string username;
                        if(m_subsystemPlayers->playerGuidGetName(it->userGuid, username))
                        {
                            chatObj.sendMessage(titleText, fmt::format("你脚下的领地是 {} 的，首付 {} $，后续续租 {} $，租用时间剩余 {} 分钟", username, it->price, it->hireMoney, it->canUseTime));
                        }
                        else
                        {
                            chatObj.sendMessage(titleText, fmt::format("你脚下的领地是其他玩家的，首付 {} $，后续续租 {} $，租用时间剩余 {} 分钟", it->price, it->hireMoney, it->canUseTime));
                            Log::Error(fmt::format("玩家领地 guid : {} 查找不到玩家", it->userGuid.toString()));
                        }
                        return;
                    }
                }
            }
            chatObj.sendMessage(titleText, "没有领地数据");
            return;
        }
        else if(cmdDataVec.size() == 2)
        {

        }
        else if(cmdDataVec.size() == 3)
        {

        }
        else if(cmdDataVec.size() >= 4)
        {

        }
        sendHelpMessage(chatObj);
    }

}
